import functools

from flask import g, jsonify, request, current_app
from flask_httpauth import HTTPBasicAuth
from jsonschema import Draft7Validator

from apps.models import User
from apps.utils.return_info import ReturnInfo

auth = HTTPBasicAuth()


@auth.verify_password
def verify_password(username_or_token):
    # first try to authenticate by token
    user = User.verify_auth_token(username_or_token)
    if not user:
        return False
    g.user = user
    return True


def verify_token_str(token):
    user = User.verify_auth_token(token)
    if not user:
        return False
    g.user = user
    return True


def verify_token_auth(allowtokennull=False, username=None, namekey=None):
    """

    :param allowtokennull: True 表示允许token为空字符串
    :param username: None 代表不验证，否则 按传入的验证，
     :param namekey: None 不验证，否则namekey的值为键，去current_app取值，usernames为None时才会判断该值是否存在
    :return:
    """

    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            jsons = request.json
            if not jsons:
                token = request.form['token']
            else:
                token = jsons.get("token")
            if token == "" and allowtokennull:
                return func(*args, **kwargs)
            ret_obj = ReturnInfo()
            user = User.verify_auth_token(token)
            if not user:
                ret_obj.msg_code = "FAILED"
                ret_obj.msg = "token 认证失败，有可能是过期"
                ret_obj.data = {"result": jsons}
                return jsonify(ret_obj.todict())
            g.user = user
            if username is not None:
                if user.username != username:
                    ret_obj.msg_code = "FAILED"
                    ret_obj.msg = "token 用户不能访问该接口"
                    return jsonify(ret_obj.todict())
            elif namekey is not None:
                usernames = current_app.config.get(namekey)
                if usernames:
                    is_true = False
                    for one_username in usernames.split(","):
                        if user.username == one_username:
                            is_true = True
                            break
                    if not is_true:
                        ret_obj.msg_code = "FAILED"
                        ret_obj.msg = "token 用户不能访问该接口"
                        return jsonify(ret_obj.todict())
                else:
                    ret_obj.msg_code = "FAILED"
                    ret_obj.msg = "无法通过key 在环境变量中获取值"
                    return jsonify(ret_obj.todict())
            return func(*args, **kwargs)

        return wrapper

    return decorator


def verify_json_schema(schema):
    validator = Draft7Validator(schema)

    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            ret_obj = ReturnInfo()
            try:
                jsons = request.json
            except Exception as e:
                ret_obj.msg_code = "FAILED"
                ret_obj.msg = "获取json异常,请检查json格式是否错误，一般为符号多余或为中文格式符号"
                ret_obj.data = {"errmsg": str(e)}
                return jsonify(ret_obj.todict())
            if jsons is None:
                ret_obj.msg_code = "FAILED"
                ret_obj.msg = "json对象不存在,检查是否以json方式请求"
                return jsonify(ret_obj.todict())
            errors = [error.message for error in validator.iter_errors(jsons)]
            if errors:
                ret_obj.msg_code = "FAILED"
                ret_obj.msg = "json对象存在错误"
                ret_obj.data = {"result": jsons, "errors": errors}
                return jsonify(ret_obj.todict())

            return func(*args, **kwargs)

        return wrapper

    return decorator
